﻿using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using Kaesoft.Hospedaje.Entities;

namespace Kaesoft.Hospedaje.Common
{
    /// <summary>
    /// Clase padre para construir nuevos view models
    /// </summary>
    public class ViewModelBase : INotifyPropertyChanged, INotifyDataErrorInfo
    {
        #region Campos Privados
        private bool _isDirty;
        private bool _enabled = true;
        private string _nombre;
        protected Opcion _opcion;
        protected bool _procesando;
        private BarraTareasViewModel _barraTareasViewModel;
        private EntityList<ErrorMessage> _errorList;
        public MessageWindowView MessageBoxWindow;
        public event EventHandler Activado;
        public event EventHandler Conectado;

        private void OnConectado()
        {
            if (Conectado != null)
                Conectado(this, new EventArgs());
        }
        
        private void OnActivado()
        {
            if (Activado != null)
                Activado(this, new EventArgs());
        }
        
        #endregion

        #region Propiedades
        public int PageSize { get { return ConfigurationManager.AppSettings["PageSize"] != null ? int.Parse(ConfigurationManager.AppSettings["PageSize"].ToString()) : 10; } }

        /// <summary>
        /// Lista de errores
        /// </summary>
        public EntityList<ErrorMessage> ErrorList
        {
            get 
            {
                if (_errorList == null)
                {
                    _errorList = new EntityList<ErrorMessage>();
                    _errorList.CollectionChanged += ErrorListCollectionChanged;
                    _errorList.CollectionClearing += ErrorListCollectionClearing;
                }

                return _errorList;
            }
        }

        /// <summary>
        /// Nombre de la pantalla
        /// </summary>
        public string Nombre
        {
            get
            {
                return _nombre;
            }
            set
            {
                if (_nombre != value)
                {
                    _nombre = value;
                    OnPropertyChanged("Nombre");
                }
            }
        }

        /// <summary>
        /// Muestra/Oculta la transición
        /// </summary>
        public bool Procesando
        {
            get
            {
                return _procesando;
            }
            set
            {
                if (_procesando != value)
                {
                    OnDisplayBusyChanged(value);
                    _procesando = value;
                    OnPropertyChanged("Procesando");
                }
            }
        }

        /// <summary>
        /// Screen is enabled or disabled (read only)
        /// </summary>
        public bool Enabled
        {
            get
            {
                return _enabled;
            }
            set
            {
                _enabled = value;
                OnPropertyChanged("Enabled");
            }
        }

        public bool IsDirty
        {
            get
            {
                return _isDirty;
            }
            set
            {
                _isDirty = value;
                OnPropertyChanged("IsDirty");
            }
        }

        /// <summary>
        /// View model de la barra de tareas
        /// </summary>
        public BarraTareasViewModel BarraTareasViewModel
        {
            get
            {
                return _barraTareasViewModel;
            }
            set
            {
                _barraTareasViewModel = value;
                OnPropertyChanged("BarraOperacion");
            }
        }

        #endregion

        #region Eventos
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler<EventArgs<bool>> DisplayBusyChanged;

        public event EventHandler<ViewModelBaseErrorArgs> OnError;
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        public event EventHandler<EventArgs<string>> ResetPager;
        #endregion

        #region Metodos Publicos
        /// <summary>
        /// Crea una instancia de la clase ViewModelBase
        /// </summary>
        public ViewModelBase()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="opcion"></param>
        public void ActivarOperaciones(Opcion opcion)
        {
            _opcion = opcion;
            if (_barraTareasViewModel != null)
            {
                _barraTareasViewModel.DesactivarOperaciones(opcion.PerfilOpcions.First().PerfilOpcionOperacions.ToList());
                OnActivado();
            }
        }

        public void NotificarDataContext(Opcion opcion)
        {
            _opcion = opcion;
            OnConectado();
        }

        /// <summary>
        /// Notifica al suscriptor el cambio del estado de la pantalla
        /// </summary>
        /// <param name="value"></param>
        public void OnDisplayBusyChanged(bool value)
        {
            if (DisplayBusyChanged != null)
                DisplayBusyChanged(this, new EventArgs<bool>(value));
        }

        /// <summary>
        /// Notifica el cambio en alguna propiedad del viewmodel
        /// </summary>
        /// <param name="propertyName"></param>
        protected void OnPropertyChanged(string propertyName)
        {
            var propertyChanged = PropertyChanged;
            if (propertyChanged != null)
                propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        protected void OnResetPager(string pagerName)
        {
            var resetPager = ResetPager;
            if (resetPager != null)
                resetPager(this, new EventArgs<string>(pagerName));
        }
        #endregion

        #region Metodos Privados
        /// <summary>
        /// Borrar la lista de errores
        /// </summary>
        void ErrorListCollectionClearing(object sender, EventArgs e)
        {
            var error = (EntityList<ErrorMessage>)sender;
            error.Where(err => err.ErrorProperty != null).ToList().ForEach(err => OnErrorsChanged(err.ErrorProperty));

            if (OnError != null)
                OnError(this, new ViewModelBaseErrorArgs(_errorList));
        }

        /// <summary>
        /// Observar cambios en la lista de errores
        /// </summary>
        void ErrorListCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null && e.NewItems.Count == 1)
            {
                ThrowErrors(_errorList);
                var error = ((ErrorMessage)e.NewItems[0]);
                if (error.ErrorProperty != null)
                    OnErrorsChanged(error.ErrorProperty);
            }
        }

        /// <summary>
        /// Notificar error en validacion
        /// </summary>
        public void OnErrorsChanged(string propertyName)
        {
            var errorsChanged = ErrorsChanged;
            if (errorsChanged != null)
                errorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Enviar lista de errores
        /// </summary>
        private void ThrowErrors(EntityList<ErrorMessage> errorList)
        {
            if (errorList.Count > 0)
            {
                var onError = OnError;
                if (onError != null)
                    OnError(this, new ViewModelBaseErrorArgs(errorList));
            }
        }
        #endregion

        #region INotifyDataErrorInfo
        public IEnumerable GetErrors(string propertyName)
        {
            return ErrorList.Where(err => err.ErrorProperty == propertyName).Select(err => err.ErrorText);
        }

        public bool HasErrors
        {
            get { return _errorList.Count() > 0; }
        }
        #endregion
    }
}